package ar.edu.itba.it.pdc.commons;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.List;

import org.joda.time.DateTime;

import com.google.common.io.LineReader;

public class Mail {

	public static String CRLF = "\r\n";
	
	private Header from;
	private DateTime date;
	private Header contentType;
	private Header contentTransferEncoding;
	protected File body;
	
	private List<Mail> parts;
	
	private List<Header> headers = new LinkedList<Header>();

	public Mail(InputStream input) {
		parseMail(input);
		if(getContentType().contains("multipart")) {
			parseParts();
		}
	}

	public void replaceWith(Mail mail) {
		this.from = mail.from;
		this.date = mail.date;
		this.contentType = mail.contentType;
		this.contentTransferEncoding = mail.contentTransferEncoding;
		this.body = mail.body;
		this.headers = mail.headers;
	}
	
	private void parseMail(InputStream input) {
		String line;
		String sheader = "";
		LineReader lis = new LineReader(new InputStreamReader(input));
		try {
			do {
				line = lis.readLine();
				if (line != null) {
					if (line.startsWith(" ") || line.startsWith("\t")) {
						sheader += line;
					} else {
						if (!sheader.isEmpty()) {
							String unfolded = POP3Utils.unfold(sheader);
							String parts[] = unfolded.split(":", 2);
							addHeader(new Header(parts[0], parts[1]));
						}
						sheader = "";
						sheader += line;
					}
				}
			} while (line != null && !line.isEmpty());

			this.body = File.createTempFile("mail_", ".madonna3", new File("tmp"));
			
			FileWriter bodyWriter = new FileWriter(this.body);
			
			while((line = lis.readLine()) != null) {
				bodyWriter.write(line + CRLF);
			}
			bodyWriter.flush();
			
		} catch (Exception e) {
		}
	}

	public void addHeader(Header header) {
		headers.add(header);
		if (header.getName().equals("Content-Type")) {
			contentType = header;
		} else if (header.getName().equals("Content-Transfer-Encoding")) {
			contentTransferEncoding = header;
		} else if (header.getName().equals("Date")) {
			date = TimeConverter.parseDateHeaderTime(header);
		} else if (header.getName().equals("From")) {
			from = header;
		}
	}

	public Iterable<Header> getHeaders() {
		return headers;
	}

	public String getUnfoldedHeaders() {
		String resp = "";
		for(Header h : getHeaders()) {
			resp += POP3Utils.unfold(h.getHeader());
			resp += "\r\n";
		}
		return resp + "\r\n";
	}
	
	public String getContentType() {
		if (contentType == null) {
			throw new InvalidPOP3FormatException("Invalid request or malformed mail");
		}
		return contentType.getValue().trim();
	}

	public Header getHeader(String name) {
		for (Header h : getHeaders()) {
			if (h.getName().equals(name)) {
				return h;
			}
		}
		return null;
	}

	public Header getFrom() {
		return from;
	}

	public DateTime getDate() {
		return date;
	}

	public Header getContentTransferEncoding() {
		return contentTransferEncoding;
	}

	public void writeTo(OutputStream out) {
		try {
			for (Header h : getHeaders()) {
				out.write(POP3Utils.fold(0, h.getHeader()).getBytes());
				out.write(CRLF.getBytes());
			}
			out.write(CRLF.getBytes());
			String b;
			LineReader body = getBody();
			while((b = body.readLine()) != null) {
				out.write(b.getBytes());
				out.write(CRLF.getBytes());
			}
		} catch (Exception e) {
		}
	}

	public LineReader getBody() {
		if(this.body == null) {
			throw new IllegalMailRequest("This mail must be deleted");
		}
		try {
			return new LineReader(new FileReader(this.body));
		} catch (Exception e) {
			return null;
		}
	}
	
	private void parseParts() {
		this.parts = new LinkedList<Mail>();
		
		String boundary = getBoundary();

		StringBuffer buf = new StringBuffer();
		String line;
		try {
			LineReader b = getBody();
			while((line = b.readLine()) != null && !line.equals("--" + boundary + "--")) {
				if(line.trim().equals("--" + boundary)) {
					if(buf.length() != 0) {
						parts.add(new Mail(new ByteArrayInputStream(buf.toString().getBytes())));
						buf.delete(0, buf.length());
					}
				}else{
					buf.append(line + CRLF);
				}
			}
			if(buf.length() != 0) {
				parts.add(new Mail(new ByteArrayInputStream(buf.toString().getBytes())));
			}
		} catch (Exception e) {
			throw new InvalidPOP3FormatException("Problems parsing multipart message:" + e.getMessage());
		}
		
	}
	
	public List<Mail> getParts() {
		return parts;
	}

	private String getBoundary() {
		return this.getContentType().split("boundary=", 2)[1];
	}

	@Override
	protected void finalize() throws Throwable {
		this.body.delete();
		super.finalize();
	}

	
}
